package services

import (
	"errors"
	"fmt"
	"gitee.com/igolang/imoney/internal/app/system/entities"
	"gitee.com/igolang/imoney/internal/app/system/entities/constants"
	"gitee.com/igolang/imoney/internal/app/system/tools"
	"gitee.com/igolang/imoney/internal/common/httpResp"
	"gitee.com/igolang/imoney/internal/models/dao"
	"gitee.com/igolang/imoney/internal/models/model"
	"gitee.com/igolang/pkg/xgorm"
	"gitee.com/igolang/pkg/xtime"
	"github.com/gin-gonic/gin"
	"github.com/spf13/cast"
	"gorm.io/gen"
	"gorm.io/gorm"
	"strings"
	"time"
)

type dept struct{}

var Dept = &dept{}

func (s *dept) List(ctx *gin.Context) ([]*model.SysDept, error) {
	var req struct {
		DeptName string `json:"deptName" form:"deptName"`
		Status   string `json:"status" form:"status"`
	}

	if err := ctx.ShouldBind(&req); err != nil {
		return nil, err
	}
	conds := make([]gen.Condition, 0)
	if req.DeptName != "" {
		conds = append(conds, dao.SysDept.DeptName.Like("%"+req.DeptName+"%"))
	}
	if req.Status != "" {
		conds = append(conds, dao.SysDept.Status.Eq(req.Status))
	}

	return dao.SysDept.Where(conds...).Order(dao.SysDept.ParentID, dao.SysDept.OrderNum).Find()
}

func (s *dept) ExcludeList(ctx *gin.Context) ([]*model.SysDept, error) {
	id := cast.ToInt64(ctx.Param("id"))
	if id == 0 {
		return nil, httpResp.ErrorCode(httpResp.ErrCodeInvalidParams)
	}
	conds := []gen.Condition{
		dao.SysDept.DeptID.Neq(id),
		dao.SysDept.Ancestors.NotLike(fmt.Sprintf(`%%,%d%%`, id)),
	}
	return dao.SysDept.Where(conds...).Find()
}

func (s *dept) Tree(status string) ([]*entities.TreeItem, error) {
	conds := make([]gen.Condition, 0)
	if status != "" {
		conds = append(conds, dao.SysDept.Status.Eq(status))
	}
	rows, err := dao.SysDept.Select(
		dao.SysDept.DeptID,
		dao.SysDept.DeptName,
		dao.SysDept.ParentID,
	).Where(conds...).Order(dao.SysDept.OrderNum).Find()

	if err != nil {
		return nil, err
	}

	list := make([]*entities.TreeItem, 0)

	if len(rows) == 0 {
		return list, nil
	}

	dataMap := make(map[int64]*entities.TreeItem)

	for _, v := range rows {
		row := v
		item := &entities.TreeItem{
			Id:       row.DeptID,
			Label:    row.DeptName,
			Children: make([]*entities.TreeItem, 0),
		}

		dataMap[row.DeptID] = item
		if row.ParentID == 0 {
			list = append(list, item)
		}
	}
	for _, v := range rows {
		if v.ParentID == 0 {
			continue
		}
		dataMap[v.ParentID].Children = append(dataMap[v.ParentID].Children, dataMap[v.DeptID])
	}

	return list, nil
}

func (s *dept) Detail(ctx *gin.Context) (*model.SysDept, error) {
	id := cast.ToInt64(ctx.Param("id"))
	if id == 0 {
		return nil, httpResp.ErrorCode(httpResp.ErrCodeInvalidParams)
	}
	return dao.SysDept.Where(dao.SysDept.DeptID.Eq(id)).Take()
}

func (s *dept) Save(ctx *gin.Context) error {
	var err error
	req := &model.SysDept{}
	if err = ctx.ShouldBind(req); err != nil {
		return err
	}

	if req.DeptName == "" {
		return httpResp.ErrorCode(httpResp.ErrCodeInvalidParams)
	}

	if req.DeptID != constants.RootDeptId && req.ParentID == 0 {
		return httpResp.ErrorCode(httpResp.ErrCodeInvalidParams)
	}

	if req.Status == "" {
		req.Status = constants.OkStatus
	}

	var oldRow *model.SysDept
	// 校验名称是否已存在
	conds := []gen.Condition{dao.SysDept.ParentID.Eq(req.ParentID), dao.SysDept.DeptName.Eq(req.DeptName)}
	if req.DeptID > 0 {
		conds = append(conds, dao.SysDept.DeptID.Neq(req.DeptID))
		oldRow, err = dao.SysDept.Where(dao.SysDept.DeptID.Eq(req.DeptID)).Take()
		if err != nil || oldRow == nil {
			return gorm.ErrRecordNotFound
		}
	}

	if total, _ := dao.SysDept.Where(conds...).Count(); total > 0 {
		return fmt.Errorf("新增部门'%s'失败，部门名称已存在", req.DeptName)
	}
	// 处理Ancestors
	oldAncestors := req.Ancestors
	if oldRow != nil {
		oldAncestors = oldRow.Ancestors
	}

	if req.ParentID > 0 {
		parentRow, err := dao.SysDept.Select(dao.SysDept.Ancestors).Where(dao.SysDept.DeptID.Eq(req.ParentID)).Take()
		if err != nil {
			return err
		}
		req.Ancestors = fmt.Sprintf("%s,%d", parentRow.Ancestors, req.ParentID)
	}
	userInfo := tools.GetUserInfo(ctx)
	req.UpdateTime = xtime.Time(time.Now())
	req.UpdateBy = userInfo.User.UserName
	// 新增
	if req.DeptID == 0 {
		req.CreateBy = userInfo.User.UserName
		req.CreateTime = xtime.Time(time.Now())
		return dao.SysDept.Create(req)
	}

	oldRow.UpdateBy = req.UpdateBy
	oldRow.UpdateTime = req.UpdateTime
	oldRow.ParentID = req.ParentID
	oldRow.DeptName = req.DeptName
	oldRow.OrderNum = req.OrderNum
	oldRow.Leader = req.Leader
	oldRow.Email = req.Email
	oldRow.Phone = req.Phone
	oldRow.Status = req.Status
	oldRow.Ancestors = req.Ancestors
	data := xgorm.ModelToMap(oldRow)
	_, err = dao.SysDept.Where(dao.SysDept.DeptID.Eq(req.DeptID)).Updates(data)
	if err != nil || req.DeptID == constants.RootDeptId {
		return err
	}

	// 没变就不用
	if oldAncestors == req.Ancestors {
		return err
	}

	// 更新子节点
	childRows, err := dao.SysDept.Select(dao.SysDept.Ancestors, dao.SysDept.DeptID).Where(dao.SysDept.Ancestors.Like(fmt.Sprintf(`%%,%d%%`, req.DeptID))).Find()
	if len(childRows) == 0 || err != nil {
		return err
	}

	for _, v := range childRows {
		ancestors := strings.ReplaceAll(v.Ancestors, oldAncestors+",", req.Ancestors+",")
		if _, e := dao.SysDept.Where(dao.SysDept.DeptID.Eq(v.DeptID)).Update(dao.SysDept.Ancestors, ancestors); e != nil {
			err = errors.Join(e)
		}
	}
	return err
}

func (s *dept) Delete(ctx *gin.Context) error {
	id := cast.ToInt64(ctx.Param("id"))
	if id == 0 {
		return httpResp.ErrorCode(httpResp.ErrCodeInvalidParams)
	}
	total, _ := dao.SysDept.Where(dao.SysDept.ParentID.Eq(id)).Count()
	if total > 0 {
		return httpResp.ErrWarning("存在下级部门,不允许删除")
	}
	if count, _ := dao.SysRoleDept.Where(dao.SysRoleDept.DeptID.Eq(id)).Count(); count > 0 {
		return httpResp.ErrWarning("部门已分配,不允许删除")
	}

	if count, _ := dao.SysUser.Where(dao.SysUser.DeptID.Eq(id)).Count(); count > 0 {
		return httpResp.ErrWarning("部门已分配用户,不允许删除")
	}

	_, err := dao.SysDept.Where(dao.SysDept.DeptID.Eq(id)).Delete()
	return err
}
